#pragma once
#include <vector>
#include <semaphore.h>

namespace Tom
{
#define DEF_CAP 10
    template<class T>
    class RingQueue
    {
    public:
        RingQueue(size_t cap = DEF_CAP)
            :_cap(cap), _pro_step(0), _con_step(0)
        {
            _queue.resize(_cap);

            sem_init(&_pro_sem, 0, _cap);
            sem_init(&_con_sem, 0, 0);
        }

        ~RingQueue()
        {
            sem_destroy(&_pro_sem);
            sem_destroy(&_con_sem);
        }

        void Push(const T& inData)
        {
            P(&_pro_sem);

            _queue[_pro_step++] = inData;
            _pro_step %= _cap;

            V(&_pro_sem);
        }

        void Pop(T* outData)
        {
            P(&_con_sem);

            *outData = _queue[_con_step++];
            _con_step %= _cap;

            V(&_pro_sem);
        }

    private:
        void P(sem_t *sem)
        {
            sem_wait(sem);
        }

        void V(sem_t *sem)
        {
            sem_post(sem);
        } 

    private:
        std::vector<T> _queue;
        size_t _cap;
        size_t _pro_step;
        size_t _con_step;
        sem_t _pro_sem;
        sem_t _con_sem;
    };  
}
